]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
sessionMode: Allow changing the session mode at runtime
authorJasper St. Pierre <jstpierre@mecheye.net>
Sat, 1 Sep 2012 12:42:53 +0000 (09:42 -0300)
committerJasper St. Pierre <jstpierre@mecheye.net>
Tue, 4 Sep 2012 21:42:44 +0000 (18:42 -0300)
Since we eventually want to add a system for changing the top panel
contents depending on the current state of the shell, let's use the
"session mode" feature for this, and add a mechanism for updating the
session mode at runtime. Add support for every key besides the two
functional keys, and make all the components update automatically when the
session mode is changed. Add a new lock-screen mode, and make the lock
screen change to this when locked.

https://bugzilla.gnome.org/show_bug.cgi?id=683156

19 files changed:
js/ui/calendar.js
js/ui/dateMenu.js
js/ui/extensionSystem.js
js/ui/layout.js
js/ui/main.js
js/ui/overview.js
js/ui/panel.js
js/ui/panelMenu.js
js/ui/popupMenu.js
js/ui/screenShield.js
js/ui/sessionMode.js
js/ui/status/accessibility.js
js/ui/status/bluetooth.js
js/ui/status/keyboard.js
js/ui/status/lockScreenMenu.js
js/ui/status/network.js
js/ui/status/power.js
js/ui/status/volume.js
js/ui/userMenu.js

index 149bf1a55d58a64d3a1647a59aac428503dca8fd..7ee01cf514e85429901a392bc6a4767b204fbbe9 100644 (file)
@@ -339,22 +339,10 @@ const DBusEventSource = new Lang.Class({
 });
 Signals.addSignalMethods(DBusEventSource.prototype);
 
-// Calendar:
-// @eventSource: is an object implementing the EventSource API, e.g. the
-// requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
 const Calendar = new Lang.Class({
     Name: 'Calendar',
 
-    _init: function(eventSource) {
-        if (eventSource) {
-            this._eventSource = eventSource;
-
-            this._eventSource.connect('changed', Lang.bind(this,
-                                                           function() {
-                                                               this._update(false);
-                                                           }));
-        }
-
+    _init: function() {
         this._weekStart = Shell.util_get_week_start();
         this._weekdate = NaN;
         this._digitWidth = NaN;
@@ -391,6 +379,24 @@ const Calendar = new Lang.Class({
         this._buildHeader ();
     },
 
+    // @eventSource: is an object implementing the EventSource API, e.g. the
+    // requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
+    setEventSource: function(eventSource) {
+        if (this._eventSource) {
+            this._eventSource.disconnect(this._eventSourceChangedId);
+            this._eventSource = null;
+        }
+
+        this._eventSource = eventSource;
+
+        if (this._eventSource) {
+            this._eventSourceChangedId = this._eventSource.connect('changed', Lang.bind(this, function() {
+                this._update(false);
+            }));
+            this._update(true);
+        }
+    },
+
     // Sets the calendar to show a specific date
     setDate: function(date, forceReload) {
         if (!_sameDay(date, this._selectedDate)) {
@@ -621,16 +627,25 @@ Signals.addSignalMethods(Calendar.prototype);
 const EventsList = new Lang.Class({
     Name: 'EventsList',
 
-    _init: function(eventSource) {
+    _init: function() {
         this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'});
         this._date = new Date();
-        this._eventSource = eventSource;
-        this._eventSource.connect('changed', Lang.bind(this, this._update));
         this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
         this._desktopSettings.connect('changed', Lang.bind(this, this._update));
         this._weekStart = Shell.util_get_week_start();
+    },
 
-        this._update();
+    setEventSource: function(eventSource) {
+        if (this._eventSource) {
+            this._eventSource.disconnect(this._eventSourceChangedId);
+            this._eventSource = null;
+        }
+
+        this._eventSource = eventSource;
+
+        if (this._eventSource) {
+            this._eventSourceChangedId = this._eventSource.connect('changed', Lang.bind(this, this._update));
+        }
     },
 
     _addEvent: function(dayNameBox, timeBox, eventTitleBox, includeDayName, day, time, desc) {
index 7a691df1084074c8937e8f626b408974bf47c933..2c455821d89ca207b545b27c4879cb4e62b22d81 100644 (file)
@@ -70,16 +70,8 @@ const DateMenuButton = new Lang.Class({
         this._date.style_class = 'datemenu-date-label';
         vbox.add(this._date);
 
-        if (Main.sessionMode.showCalendarEvents) {
-            this._eventSource = new Calendar.DBusEventSource();
-            this._eventList = new Calendar.EventsList(this._eventSource);
-        } else {
-            this._eventSource = null;
-            this._eventList = null;
-        }
-
-        // Calendar
-        this._calendar = new Calendar.Calendar(this._eventSource);
+        this._eventList = new Calendar.EventsList();
+        this._calendar = new Calendar.Calendar();
 
         this._calendar.connect('selected-date-changed',
                                Lang.bind(this, function(calendar, date) {
@@ -101,27 +93,23 @@ const DateMenuButton = new Lang.Class({
             item.actor.reparent(vbox);
         }
 
-        if (Main.sessionMode.showCalendarEvents) {
-            // Add vertical separator
-
-            item = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
-                                        pseudo_class: 'highlighted' });
-            item.connect('repaint', Lang.bind(this, _onVertSepRepaint));
-            hbox.add(item);
+        this._separator = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
+                                               pseudo_class: 'highlighted' });
+        this._separator.connect('repaint', Lang.bind(this, _onVertSepRepaint));
+        hbox.add(this._separator);
 
-            // Fill up the second column
-            vbox = new St.BoxLayout({name:     'calendarEventsArea',
-                                     vertical: true});
-            hbox.add(vbox, { expand: true });
+        // Fill up the second column
+        vbox = new St.BoxLayout({ name: 'calendarEventsArea',
+                                  vertical: true });
+        hbox.add(vbox, { expand: true });
 
-            // Event list
-            vbox.add(this._eventList.actor, { expand: true });
+        // Event list
+        vbox.add(this._eventList.actor, { expand: true });
 
-            item = new PopupMenu.PopupMenuItem(_("Open Calendar"));
-            item.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
-            item.actor.can_focus = false;
-            vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
-        }
+        this._openCalendarItem = new PopupMenu.PopupMenuItem(_("Open Calendar"));
+        this._openCalendarItem.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
+        this._openCalendarItem.actor.can_focus = false;
+        vbox.add(this._openCalendarItem.actor, {y_align: St.Align.END, expand: true, y_fill: false});
 
         // Whenever the menu is opened, select today
         this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
@@ -151,6 +139,32 @@ const DateMenuButton = new Lang.Class({
         this._clock = new GnomeDesktop.WallClock();
         this._clock.connect('notify::clock', Lang.bind(this, this._updateClockAndDate));
         this._updateClockAndDate();
+
+        Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
+        this._sessionUpdated();
+    },
+
+    _setEventsVisibility: function(visible) {
+        this._separator.visible = visible;
+        this._eventList.visible = visible;
+        this._openCalendarItem.visible = visible;
+    },
+
+    _setEventSource: function(eventSource) {
+        this._calendar.setEventSource(eventSource);
+        this._eventList.setEventSource(eventSource);
+    },
+
+    _sessionUpdated: function() {
+        let eventSource;
+        let showEvents = Main.sessionMode.showCalendarEvents;
+        if (showEvents) {
+            eventSource = new Calendar.DBusEventSource();
+        } else {
+            eventSource = null;
+        }
+        this._setEventSource(eventSource);
+        this._setEventsVisibility(showEvents);
     },
 
     _updateClockAndDate: function() {
index 4eb49c10fd2032f93ca342092b5b459f4d020454..6129370ec0e1bb5a7f61897ef0627385b1067d04 100644 (file)
@@ -8,6 +8,7 @@ const Gio = imports.gi.Gio;
 const St = imports.gi.St;
 
 const ExtensionUtils = imports.misc.extensionUtils;
+const Main = imports.ui.main;
 
 const ExtensionState = {
     ENABLED: 1,
@@ -38,6 +39,9 @@ const disconnect = Lang.bind(_signals, _signals.disconnect);
 
 const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
 
+var initted = false;
+var enabled;
+
 function disableExtension(uuid) {
     let extension = ExtensionUtils.extensions[uuid];
     if (!extension)
@@ -216,6 +220,9 @@ function initExtension(uuid) {
 function onEnabledExtensionsChanged() {
     let newEnabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
 
+    if (!enabled)
+        return;
+
     // Find and enable all the newly enabled extensions: UUIDs found in the
     // new setting, but not in the old one.
     newEnabledExtensions.filter(function(uuid) {
@@ -243,7 +250,7 @@ function onEnabledExtensionsChanged() {
     enabledExtensions = newEnabledExtensions;
 }
 
-function loadExtensions() {
+function _loadExtensions() {
     global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
     enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
 
@@ -257,3 +264,43 @@ function loadExtensions() {
     });
     finder.scanExtensions();
 }
+
+function enableAllExtensions() {
+    if (enabled)
+        return;
+
+    if (!initted) {
+        _loadExtensions();
+        initted = true;
+    } else {
+        enabledExtensions.forEach(function(uuid) {
+            enableExtension(uuid);
+        });
+    }
+    enabled = true;
+}
+
+function disableAllExtensions() {
+    if (!enabled)
+        return;
+
+    if (initted) {
+        enabledExtensions.forEach(function(uuid) {
+            disableExtension(uuid);
+        });
+    }
+
+    enabled = false;
+}
+
+function _sessionUpdated() {
+    if (Main.sessionMode.allowExtensions)
+        enableAllExtensions();
+    else
+        disableAllExtensions();
+}
+
+function init() {
+    Main.sessionMode.connect('updated', _sessionUpdated);
+    _sessionUpdated();
+}
index 9f1cf611b255b4759f0ea159ee4b8f7f8121ae6d..d2daafead0e7e4651da95883f8282baee3932294 100644 (file)
@@ -639,7 +639,6 @@ const Chrome = new Lang.Class({
 
         this._monitors = [];
         this._inOverview = false;
-        this._isLocked = false;
         this._updateRegionIdle = 0;
         this._freezeUpdateCount = 0;
 
@@ -658,12 +657,9 @@ const Chrome = new Lang.Class({
     },
 
     init: function() {
-        Main.overview.connect('showing',
-                             Lang.bind(this, this._overviewShowing));
-        Main.overview.connect('hidden',
-                             Lang.bind(this, this._overviewHidden));
-        Main.screenShield.connect('lock-status-changed',
-                                  Lang.bind(this, this._lockStatusChanged));
+        Main.overview.connect('showing', Lang.bind(this, this._overviewShowing));
+        Main.overview.connect('hidden', Lang.bind(this, this._overviewHidden));
+        Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
     },
 
     addActor: function(actor, params) {
@@ -763,7 +759,7 @@ const Chrome = new Lang.Class({
             if (!actorData.isToplevel)
                 continue;
 
-            if (this._inOverview || this._isLocked)
+            if (this._inOverview || Main.sessionMode.hasWindows)
                 visible = true;
             else if (this.findMonitorForActor(actorData.actor).inFullscreen)
                 visible = false;
@@ -785,8 +781,7 @@ const Chrome = new Lang.Class({
         this._queueUpdateRegions();
     },
 
-    _lockStatusChanged: function(shield, locked) {
-        this._isLocked = locked;
+    _sessionUpdated: function() {
         this._updateVisibility();
         this._queueUpdateRegions();
     },
index 3bb05c6689896a83ba7cefbdb0b3d879f4843f1e..1d8ad4c95085c3cfdfc48164dbf3bd2af55884f5 100644 (file)
@@ -143,6 +143,11 @@ function _initRecorder() {
     });
 }
 
+function _sessionUpdated() {
+    Meta.keybindings_set_custom_handler('panel-run-dialog', sessionMode.hasRunDialog ? openRunDialog : null);
+    loadTheme();
+}
+
 function start() {
     // These are here so we don't break compatibility.
     global.logError = window.log;
@@ -217,29 +222,17 @@ function start() {
 
     sessionMode.createSession();
 
-    panel.init();
     layoutManager.init();
     keyboard.init();
     overview.init();
 
-    if (sessionMode.hasWorkspaces)
-        global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
-                                                false, -1, 1);
-
-    if (sessionMode.hasRunDialog) {
-        Meta.keybindings_set_custom_handler('panel-run-dialog', function() {
-           getRunDialog().open();
-        });
-    }
-
-    if (sessionMode.hasOverview) {
-        Meta.keybindings_set_custom_handler('panel-main-menu', function () {
-            overview.toggle();
-        });
+    global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
+                                            false, -1, 1);
+    Meta.keybindings_set_custom_handler('panel-main-menu', Lang.bind(overview, overview.toggle));
+    global.display.connect('overlay-key', Lang.bind(overview, overview.toggle));
 
-        global.display.connect('overlay-key',
-                               Lang.bind(overview, overview.toggle));
-    }
+    sessionMode.connect('update', _sessionUpdated);
+    _sessionUpdated();
 
     // Provide the bus object for gnome-session to
     // initiate logouts.
@@ -275,10 +268,8 @@ function start() {
 
     _nWorkspacesChanged();
 
-    if (sessionMode.allowExtensions) {
-        ExtensionDownloader.init();
-        ExtensionSystem.loadExtensions();
-    }
+    ExtensionDownloader.init();
+    ExtensionSystem.init();
 }
 
 let _workspaces = [];
@@ -617,7 +608,7 @@ function _globalKeyPressHandler(actor, event) {
             if (!sessionMode.hasRunDialog)
                 return false;
 
-            getRunDialog().open();
+            openRunDialog();
             return true;
         case Meta.KeyBindingAction.PANEL_MAIN_MENU:
         case Meta.KeyBindingAction.OVERLAY_KEY:
@@ -763,11 +754,11 @@ function createLookingGlass() {
     return lookingGlass;
 }
 
-function getRunDialog() {
+function openRunDialog() {
     if (runDialog == null) {
         runDialog = new RunDialog.RunDialog();
     }
-    return runDialog;
+    runDialog.open();
 }
 
 /**
index a319a3bf929cff06a3c65c1c87e0376cbd051386..eab79ff03ad7fff2877e4497e3a36519a97e8292 100644 (file)
@@ -92,16 +92,21 @@ const ShellInfo = new Lang.Class({
 const Overview = new Lang.Class({
     Name: 'Overview',
 
-    _init : function() {
-        this.isDummy = !Main.sessionMode.hasOverview;
+    _init: function() {
+        this._overviewCreated = false;
+
+        Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
+        this._sessionUpdated();
+    },
 
-        // We only have an overview in user sessions, so
-        // create a dummy overview in other cases
-        if (this.isDummy) {
-            this.animationInProgress = false;
-            this.visible = false;
+    _createOverview: function() {
+        if (this._overviewCreated)
             return;
-        }
+
+        if (this.isDummy)
+            return;
+
+        this._overviewCreated = true;
 
         // The main BackgroundActor is inside global.window_group which is
         // hidden when displaying the overview, so we create a new
@@ -174,6 +179,11 @@ const Overview = new Lang.Class({
         this._needsFakePointerEvent = false;
     },
 
+    _sessionUpdated: function() {
+        this.isDummy = !Main.sessionMode.hasOverview;
+        this._createOverview();
+    },
+
     // The members we construct that are implemented in JS might
     // want to access the overview as Main.overview to connect
     // signal handlers and so forth. So we create them after
index a3a6aac66a1257b6afe9d80fa841b87dbcea70a7..5c4a0b2e08a4e20c232c3b9bc56098d3b82610e9 100644 (file)
@@ -468,15 +468,6 @@ const AppMenuButton = new Lang.Class({
         this._sync();
     },
 
-    setLockedState: function(locked) {
-        if (locked) {
-            this.hide();
-        } else {
-            this.show();
-            this._sync();
-        }
-    },
-
     _sync: function() {
         let tracker = Shell.WindowTracker.get_default();
         let focusedApp = tracker.focus_app;
@@ -943,8 +934,6 @@ const Panel = new Lang.Class({
             this.actor.remove_style_class_name('in-overview');
         }));
 
-        Main.screenShield.connect('lock-status-changed', Lang.bind(this, this._onLockStateChanged));
-
         this.menuManager = new PopupMenu.PopupMenuManager(this);
 
         this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
@@ -975,6 +964,9 @@ const Panel = new Lang.Class({
         Main.layoutManager.panelBox.add(this.actor);
         Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'start-here-symbolic',
                                         { sortGroup: CtrlAltTab.SortGroup.TOP });
+
+        Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
+        this._updatePanel();
     },
 
     _getPreferredWidth: function(actor, forHeight, alloc) {
@@ -1103,11 +1095,27 @@ const Panel = new Lang.Class({
         menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
     },
 
-    init: function() {
+    set boxOpacity(value) {
+        let isReactive = value > 0;
+
+        this._leftBox.opacity = value;
+        this._leftBox.reactive = isReactive;
+        this._centerBox.opacity = value;
+        this._centerBox.reactive = isReactive;
+        this._rightBox.opacity = value;
+        this._rightBox.reactive = isReactive;
+    },
+
+    get boxOpacity() {
+        return this._leftBox.opacity;
+    },
+
+    _updatePanel: function() {
         let panel = Main.sessionMode.panel;
-        this._initBox(panel.left, this._leftBox);
-        this._initBox(panel.center, this._centerBox);
-        this._initBox(panel.right, this._rightBox);
+        this._hideIndicators();
+        this._updateBox(panel.left, this._leftBox);
+        this._updateBox(panel.center, this._centerBox);
+        this._updateBox(panel.right, this._rightBox);
     },
 
     _initBox: function(elements, box) {
@@ -1119,20 +1127,97 @@ const Panel = new Lang.Class({
                 // bluetooth or network)
                 continue;
             }
+        }
+    },
+
+    _tweenAndUpdatePanel: function() {
+        this._closeIndicatorMenus();
+
+        Tweener.addTween(this, {
+            boxOpacity: 0,
+            time: Overview.ANIMATION_TIME / 2,
+            transition: 'easeOutQuad',
+            onCompleteScope: this,
+            onComplete: function() {
+                this._updatePanel();
+                Tweener.addTween(this, {
+                    boxOpacity: 255,
+                    time: Overview.ANIMATION_TIME / 2,
+                    transition: 'easeOutQuad'
+                });
+            }
+        });
+    },
+
+    _sessionUpdated: function() {
+        this._tweenAndUpdatePanel();
+    },
+
+    _closeIndicatorMenus: function() {
+        for (let role in this.statusArea) {
+            let indicator = this.statusArea[role];
+            indicator.menu.close();
+        }
+    },
+
+    _hideIndicators: function() {
+        for (let role in PANEL_ITEM_IMPLEMENTATIONS) {
+            let indicator = this.statusArea[role];
+            if (!indicator)
+                continue;
+            indicator._panelContainer.hide();
+        }
+    },
+
+    _ensureIndicator: function(role) {
+        let indicator = this.statusArea[role];
+        if (!indicator) {
+            let constructor = PANEL_ITEM_IMPLEMENTATIONS[role];
+            if (!constructor) {
+                // This icon is not implemented (this is a bug)
+                return null;
+            }
+            indicator = new constructor(this);
+            this.statusArea[role] = indicator;
+        }
+        return indicator;
+    },
+
+    _updateBox: function(elements, box) {
+        let nChildren = box.get_n_children();
+
+        for (let i = 0; i < elements.length; i++) {
+            let role = elements[i];
+            let indicator = this._ensureIndicator(role);
+            if (indicator == null)
+                continue;
 
-            let indicator = new constructor(this);
-            this._addToPanelBox(role, indicator, i, box);
+            this._addToPanelBox(role, indicator, i + nChildren, box);
         }
     },
 
     _addToPanelBox: function(role, indicator, position, box) {
-        box.insert_child_at_index(indicator.actor, position);
+        let container = indicator._panelContainer;
+        if (!container) {
+            container = new St.Bin({ y_fill: true,
+                                     child: indicator.actor });
+            indicator._panelContainer = container;
+        }
+        container.show();
+
+        let parent = container.get_parent();
+        if (parent) {
+            parent.remove_actor(container);
+        }
+
+        box.insert_child_at_index(container, position);
         if (indicator.menu)
             this.menuManager.addMenu(indicator.menu);
         this.statusArea[role] = indicator;
         let destroyId = indicator.connect('destroy', Lang.bind(this, function(emitter) {
             delete this.statusArea[role];
             emitter.disconnect(destroyId);
+            container.destroy();
         }));
     },
 
@@ -1150,12 +1235,8 @@ const Panel = new Lang.Class({
             right: this._rightBox
         };
         let boxContainer = boxes[box] || this._rightBox;
+        this.statusArea[role] = indicator;
         this._addToPanelBox(role, indicator, position, boxContainer);
         return indicator;
-    },
-
-    _onLockStateChanged: function(shield, locked) {
-        for (let id in this.statusArea)
-            this.statusArea[id].setLockedState(locked);
-    },
+    }
 });
index 0983a92bd8fefc2495e73471383c87b573195387..28b9851a55913af099f69791aa0989e27686a540 100644 (file)
@@ -146,13 +146,6 @@ const Button = new Lang.Class({
         }
     },
 
-    setLockedState: function(locked) {
-        // default behaviour is to hide completely
-        if (locked)
-            this.menu.close();
-        this.actor.visible = !locked;
-    },
-
     _onButtonPress: function(actor, event) {
         if (!this.menu)
             return;
index cb3f05d05032c3041d2730f3a97843c32a29e419..5eba45f3aae25c687d6ca3667f9ceebae1a87a0d 100644 (file)
@@ -870,6 +870,12 @@ const PopupMenuBase = new Lang.Class({
         this._activeMenuItem = null;
         this._childMenus = [];
         this._settingsActions = { };
+
+        this._sessionUpdatedId = Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
+    },
+
+    _sessionUpdated: function() {
+        this._setSettingsVisibility(Main.sessionMode.allowSettings);
     },
 
     addAction: function(title, callback) {
@@ -883,9 +889,6 @@ const PopupMenuBase = new Lang.Class({
     },
 
     addSettingsAction: function(title, desktopFile) {
-        if (!Main.sessionMode.allowSettings)
-            return null;
-
         let menuItem = this.addAction(title, function() {
                            let app = Shell.AppSystem.get_default().lookup_setting(desktopFile);
 
@@ -903,7 +906,7 @@ const PopupMenuBase = new Lang.Class({
         return menuItem;
     },
 
-    setSettingsVisibility: function(visible) {
+    _setSettingsVisibility: function(visible) {
         for (let id in this._settingsActions) {
             let item = this._settingsActions[id];
             item.actor.visible = visible;
@@ -1172,6 +1175,9 @@ const PopupMenuBase = new Lang.Class({
         this.actor.destroy();
 
         this.emit('destroy');
+
+        Main.sessionMode.disconnect(this._sessionUpdatedId);
+        this._sessionUpdatedId = 0;
     }
 });
 Signals.addSignalMethods(PopupMenuBase.prototype);
@@ -2041,6 +2047,9 @@ const PopupMenuManager = new Lang.Class({
     },
 
     addMenu: function(menu, position) {
+        if (this._findMenu(menu) > -1)
+            return;
+
         let menudata = {
             menu:              menu,
             openStateChangeId: menu.connect('open-state-changed', Lang.bind(this, this._onMenuOpenState)),
index 1a10106a3ca5db0f0cae0aeba45b516135d92180..2acea47bd3b2691d789b0cab4e405aa2ee1219c4 100644 (file)
@@ -735,6 +735,9 @@ const ScreenShield = new Lang.Class({
     },
 
     unlock: function() {
+        if (!this._isLocked)
+            return;
+
         if (this._hasLockScreen)
             this._clearLockScreen();
 
@@ -762,9 +765,13 @@ const ScreenShield = new Lang.Class({
         this.actor.hide();
 
         this.emit('lock-status-changed', false);
+        Main.sessionMode.popMode('lock-screen');
     },
 
     lock: function(animate) {
+        if (this._isLocked)
+            return;
+
         if (!this._hasLockScreen)
             this._prepareLockScreen();
 
@@ -778,6 +785,7 @@ const ScreenShield = new Lang.Class({
         this._resetLockScreen(animate);
 
         this.emit('lock-status-changed', true);
+        Main.sessionMode.pushMode('lock-screen');
     },
 });
 Signals.addSignalMethods(ScreenShield.prototype);
index 950bda2be0ce20acd34c764bb35c0f38ad8ad32c..09c05608ec3ece03ec062db364005979da409f8e 100644 (file)
@@ -1,6 +1,7 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 
 const Lang = imports.lang;
+const Signals = imports.signals;
 
 const Main = imports.ui.main;
 const Params = imports.misc.params;
@@ -15,16 +16,33 @@ const _modes = {
              allowKeybindingsWhenModal: true,
              hasRunDialog: false,
              hasWorkspaces: false,
+             hasWindows: false,
              createSession: Main.createGDMSession,
              createUnlockDialog: Main.createGDMLoginDialog,
              panel: {
                  left: [],
                  center: ['dateMenu'],
                  right: ['a11y', 'display', 'keyboard',
-                         'volume', 'battery', 'lockScreen', 'powerMenu']
+                         'volume', 'battery', 'powerMenu']
              }
            },
 
+    'lock-screen': {
+        hasOverview: false,
+        showCalendarEvents: false,
+        allowSettings: false,
+        allowExtensions: false,
+        allowKeybindingsWhenModal: false,
+        hasRunDialog: false,
+        hasWorkspaces: false,
+        hasWindows: false,
+        panel: {
+            left: ['userMenu'],
+            center: [],
+            right: ['lockScreen']
+        },
+    },
+
     'initial-setup': { hasOverview: false,
                        showCalendarEvents: false,
                        allowSettings: false,
@@ -36,7 +54,7 @@ const _modes = {
                        panel: {
                            left: [],
                            center: ['dateMenu'],
-                           right: ['a11y', 'keyboard', 'volume', 'lockScreen']
+                           right: ['a11y', 'keyboard', 'volume']
                        }
                      },
 
@@ -47,13 +65,14 @@ const _modes = {
               allowKeybindingsWhenModal: false,
               hasRunDialog: true,
               hasWorkspaces: true,
+              hasWindows: true,
               createSession: Main.createUserSession,
               createUnlockDialog: Main.createSessionUnlockDialog,
               panel: {
                   left: ['activities', 'appMenu'],
                   center: ['dateMenu'],
                   right: ['a11y', 'keyboard', 'volume', 'bluetooth',
-                          'network', 'battery', 'lockScreen', 'userMenu']
+                          'network', 'battery', 'userMenu']
               }
             }
 };
@@ -68,8 +87,29 @@ const SessionMode = new Lang.Class({
     Name: 'SessionMode',
 
     _init: function() {
-        let params = _modes[global.session_mode];
+        global.connect('notify::session-mode', Lang.bind(this, this._sync));
+        this._modeStack = [global.session_mode];
+        this._sync();
+    },
+
+    pushMode: function(mode) {
+        this._modeStack.push(mode);
+        this._sync();
+    },
+
+    popMode: function(mode) {
+        if (this.currentMode != mode || this._modeStack.length === 1)
+            throw new Error("Invalid SessionMode.popMode");
+        this._modeStack.pop();
+        this._sync();
+    },
+
+    get currentMode() {
+        return this._modeStack[this._modeStack.length - 1];
+    },
 
+    _sync: function() {
+        let params = _modes[this.currentMode];
         params = Params.parse(params, _modes[DEFAULT_MODE]);
 
         this._createSession = params.createSession;
@@ -78,6 +118,7 @@ const SessionMode = new Lang.Class({
         delete params.createUnlockDialog;
 
         Lang.copyProperties(params, this);
+        this.emit('updated');
     },
 
     createSession: function() {
@@ -92,3 +133,4 @@ const SessionMode = new Lang.Class({
             return null;
     },
 });
+Signals.addSignalMethods(SessionMode.prototype);
index d06dd25c7d25d886d0457406b6a6f42fc3bda1ad..0c4f1ca507e341500a83e81b9537e450cbc3a200 100644 (file)
@@ -75,10 +75,6 @@ const ATIndicator = new Lang.Class({
         this.menu.addSettingsAction(_("Universal Access Settings"), 'gnome-universal-access-panel.desktop');
     },
 
-    setLockedState: function(locked) {
-        this.actor.visible = !locked;
-    },
-
     _buildItemExtended: function(string, initial_value, writable, on_set) {
         let widget = new PopupMenu.PopupSwitchMenuItem(string, initial_value);
         if (!writable)
index 5a2609ca66b2ff294460a829a7b10165de11166e..3e043c375597f4ab0b94620821c3dbab72d94bc9 100644 (file)
@@ -88,11 +88,6 @@ const Indicator = new Lang.Class({
         this._applet.connect('cancel-request', Lang.bind(this, this._cancelRequest));
     },
 
-    setLockedState: function(locked) {
-        this._isLocked = locked;
-        this._updateKillswitch();
-    },
-
     _updateKillswitch: function() {
         let current_state = this._applet.killswitch_state;
         let on = current_state == GnomeBluetooth.KillswitchState.UNBLOCKED;
@@ -107,7 +102,7 @@ const Indicator = new Lang.Class({
             /* TRANSLATORS: this means that bluetooth was disabled by hardware rfkill */
             this._killswitch.setStatus(_("hardware disabled"));
 
-        this.actor.visible = !this._isLocked && has_adapter;
+        this.actor.visible = has_adapter;
 
         if (on) {
             this._discoverable.actor.show();
index 900c81cd8542f3131a37a03146f5e72342dd12db..4299af620c88dab46723a105e88e1c3d914d4c61 100644 (file)
@@ -166,22 +166,21 @@ const InputSourceIndicator = new Lang.Class({
 
         this._inputSourcesChanged();
 
+        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
+        this._showLayoutItem = this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, this._showLayout));
+
+        Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
+        this._sessionUpdated();
+
+        this.menu.addSettingsAction(_("Region and Language Settings"), 'gnome-region-panel.desktop');
+    },
+
+    _sessionUpdated: function() {
         // re-using "allowSettings" for the keyboard layout is a bit shady,
         // but at least for now it is used as "allow popping up windows
         // from shell menus"; we can always add a separate sessionMode
         // option if need arises.
-        if (Main.sessionMode.allowSettings) {
-            this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
-            this._showLayoutItem = this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, this._showLayout));
-        }
-        this.menu.addSettingsAction(_("Region and Language Settings"), 'gnome-region-panel.desktop');
-    },
-
-    setLockedState: function(locked) {
-        if (Main.sessionMode.allowSettings) {
-            this._showLayoutItem.actor.visible = !locked;
-        }
-        this.menu.setSettingsVisibility(!locked);
+        this._showLayoutItem.visible = Main.sessionMode.allowSettings;
     },
 
     _currentInputSourceChanged: function() {
index 6f8b897ae2738fc92ff5e4c713230cd38e5ed5ee..d47a7c17fbd11a0b29502971f3b39dd221af1fb6 100644 (file)
@@ -16,7 +16,6 @@ const Indicator = new Lang.Class({
 
     _init: function() {
         this.parent(null, _("Volume, network, battery"));
-        this.actor.hide();
 
         this._volume = Main.panel.statusArea.volume;
         if (this._volume) {
@@ -54,9 +53,5 @@ const Indicator = new Lang.Class({
             this._battery.mainIcon.bind_property('visible', this._batteryIcon, 'visible',
                                                  GObject.BindingFlags.SYNC_CREATE);
         }
-    },
-
-    setLockedState: function(locked) {
-        this.actor.visible = locked;
     }
 });
index 23f620718dd607b197472f8e39a8e0032de3aff2..c36ceb38d83dff2cf7726003d0f8540b97d8b0be 100644 (file)
@@ -1567,7 +1567,6 @@ const NMApplet = new Lang.Class({
         this.secondaryIcon = this.addIcon(new Gio.ThemedIcon({ name: 'network-vpn-symbolic' }));
         this.secondaryIcon.hide();
 
-        this._isLocked = false;
         this._client = NMClient.Client.new();
 
         this._statusSection = new PopupMenu.PopupMenuSection();
@@ -1675,11 +1674,6 @@ const NMApplet = new Lang.Class({
         }));
     },
 
-    setLockedState: function(locked) {
-        this._isLocked = locked;
-        this._syncNMState();
-    },
-
     _ensureSource: function() {
         if (!this._source) {
             this._source = new MessageTray.Source(_("Network Manager"),
@@ -2063,7 +2057,7 @@ const NMApplet = new Lang.Class({
 
     _syncNMState: function() {
         this.mainIcon.visible = this._client.manager_running;
-        this.actor.visible = this.mainIcon.visible && !this._isLocked;
+        this.actor.visible = this.mainIcon.visible;
 
         if (!this._client.networking_enabled) {
             this.setIcon('network-offline-symbolic');
index 1669734a23dbe3aab6f9f19f275c052c8af9307a..a5f2625f5e029dbfe909ddcec9c26961c62d4d84 100644 (file)
@@ -56,7 +56,6 @@ const Indicator = new Lang.Class({
 
         this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
 
-        this._isLocked = false;
         this._deviceItems = [ ];
         this._hasPrimary = false;
         this._primaryDeviceId = null;
@@ -77,11 +76,6 @@ const Indicator = new Lang.Class({
         this._devicesChanged();
     },
 
-    setLockedState: function(locked) {
-        this._isLocked = locked;
-        this._syncIcon();
-    },
-
     _readPrimaryDevice: function() {
         this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(result, error) {
             if (error) {
@@ -160,7 +154,7 @@ const Indicator = new Lang.Class({
             hasIcon = true;
         }
         this.mainIcon.visible = hasIcon;
-        this.actor.visible = hasIcon && !this._isLocked;
+        this.actor.visible = hasIcon;
     },
 
     _devicesChanged: function() {
index 4cc9ff7377151830a03164f11a366fe688df5d88..e0bebede237b6b58f5fea6a2db7c222522f1f2d4 100644 (file)
@@ -217,8 +217,6 @@ const Indicator = new Lang.Class({
     _init: function() {
         this.parent('audio-volume-muted-symbolic', _("Volume"));
 
-        this._isLocked = false;
-
         this._control = getMixerControl();
         this._volumeMenu = new VolumeMenu(this._control);
         this._volumeMenu.connect('icon-changed', Lang.bind(this, function(menu, icon) {
@@ -235,13 +233,8 @@ const Indicator = new Lang.Class({
         this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
     },
 
-    setLockedState: function(locked) {
-        this._isLocked = locked;
-        this._syncVisibility();
-    },
-
     _syncVisibility: function() {
-        this.actor.visible = this._hasPulseAudio && !this._isLocked;
+        this.actor.visible = this._hasPulseAudio;
         this.mainIcon.visible = this._hasPulseAudio;
     },
 
index bc09df8decf7daa0ba2440fbe40fe4bd3a15390f..49b22261ca168945971988d7a666b55a8c357d52 100644 (file)
@@ -58,6 +58,11 @@ const UserAvatarWidget = new Lang.Class({
                                   reactive: params.reactive });
     },
 
+    setSensitive: function(sensitive) {
+        this.actor.can_focus = sensitive;
+        this.actor.reactive = sensitive;
+    },
+
     update: function() {
         let iconFile = this._user.get_icon_file();
         if (!GLib.file_test(iconFile, GLib.FileTest.EXISTS))
@@ -236,6 +241,10 @@ const IMStatusChooserItem = new Lang.Class({
             if (this.actor.mapped)
                 this._updateUser();
         }));
+
+        this.connect('sensitive-changed', function(sensitive) {
+            this._avatar.setSensitive(sensitive);
+        });
     },
 
     _restorePresence: function() {
@@ -560,10 +569,15 @@ const UserMenuButton = new Lang.Class({
                                        Lang.bind(this, this._updateHaveShutdown));
 
         this._upClient.connect('notify::can-suspend', Lang.bind(this, this._updateSuspendOrPowerOff));
+
+        Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
+        this._sessionUpdated();
     },
 
-    setLockedState: function(locked) {
-        this.actor.visible = !locked;
+    _sessionUpdated: function() {
+        let allowSettings = Main.sessionMode.allowSettings;
+        this._statusChooser.setSensitive(allowSettings);
+        this._systemSettings.visible = allowSettings;
     },
 
     _onDestroy: function() {
@@ -707,8 +721,7 @@ const UserMenuButton = new Lang.Class({
         let item;
 
         item = new IMStatusChooserItem();
-        if (Main.sessionMode.allowSettings)
-            item.connect('activate', Lang.bind(this, this._onMyAccountActivate));
+        item.connect('activate', Lang.bind(this, this._onMyAccountActivate));
         this.menu.addMenuItem(item);
         this._statusChooser = item;
 
@@ -720,11 +733,10 @@ const UserMenuButton = new Lang.Class({
         item = new PopupMenu.PopupSeparatorMenuItem();
         this.menu.addMenuItem(item);
 
-        if (Main.sessionMode.allowSettings) {
-            item = new PopupMenu.PopupMenuItem(_("System Settings"));
-            item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
-            this.menu.addMenuItem(item);
-        }
+        item = new PopupMenu.PopupMenuItem(_("System Settings"));
+        item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
+        this.menu.addMenuItem(item);
+        this._systemSettings = item;
 
         item = new PopupMenu.PopupSeparatorMenuItem();
         this.menu.addMenuItem(item);